package cn.digitalize.common.util.bean;

import cn.digitalize.common.util.exception.CommonUtilException;
import net.sf.cglib.beans.BeanCopier;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author Created by ZhangCheng on 2023/06/02 (属性拷贝工具类)
 */
public class CopyUtil {

    /**
     * 缓存BeanCopier实例
     */
    private static final Map<String, BeanCopier> BEAN_COPIER_MAP = new ConcurrentHashMap<>();

    private CopyUtil() {
    }

    /**
     * Cglib BeanCopier对象属性拷贝
     *
     * @param source 源对象
     * @param target 目标对象
     */
    public static void copyProperties(Object source, Object target) {
        BeanCopier beanCopier = getBeanCopier(source.getClass(), target.getClass());
        beanCopier.copy(source, target, null);
    }

    /**
     * 对象属性转换
     *
     * @param source 源对象
     * @param clazz  目标对象类
     * @param <T>
     * @return
     */
    public static <T> T convert(Object source, Class<T> clazz) {
        T result;
        try {
            result = clazz.newInstance();
        } catch (IllegalAccessException | InstantiationException e) {
            throw new CommonUtilException("拷贝对象实例创建失败：" + clazz.getCanonicalName(), e);
        }
        copyProperties(source, result);
        return result;
    }

    /**
     * List对象属性转换
     *
     * @param sourceList 源对象List
     * @param clazz      目标对象类
     * @param <T>
     * @return
     */
    public static <T> List<T> convertList(List<?> sourceList, Class<T> clazz) {
        if (sourceList == null || sourceList.isEmpty()) {
            return Collections.emptyList();
        }
        List<T> resultList =sourceList.stream().map(source->convert(source,clazz)).collect(Collectors.toList());
        return resultList;
    }

    /**
     * 从缓存中获取BeanCopier
     *
     * @param source 源对象
     * @param target 目标对象
     * @return
     */
    private static BeanCopier getBeanCopier(Class<?> source, Class<?> target) {
        String key = generateKey(source, target);
        return BEAN_COPIER_MAP.computeIfAbsent(key, x -> BeanCopier.create(source, target, false));
    }

    /**
     * 拼接Map中key
     * 实例："abc".concat("123"); 结果:abc123
     *
     * @param source 源对象
     * @param target 目标对象
     * @return
     */
    private static String generateKey(Class<?> source, Class<?> target) {
        return source.getCanonicalName().concat(target.getCanonicalName());
    }
}
